﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DbDoc.BusinessManager;
using DbDoc.BusinessObjects;
using System.Collections.ObjectModel;
using System.Threading;
using System.ComponentModel;
using DbDoc.PowerDoc.Model;
using System.Windows;
using DbDoc.PowerDoc.Properties;
using System.Windows.Threading;


namespace DbDoc.PowerDoc.ViewModel
{
    public class MainViewModel : ViewModelBase
    {
        #region Member Variables

        private Window _CurrentView;
        private AppUser _LoggedUser;

        private object synchronizationObject = new object();        
        private ObservableCollection<Database> _Databases;
        private ObservableCollection<DatabaseModel> _DatabasesModel;


        private DbObjectModel _SelectedObject;
        private DelegateCommand _RefreshCommand;
        private DelegateCommand _SynchronizeCommand;
        private DelegateCommand _UpdateSelectedObjectCommand;
        private DelegateCommand _ExitCommand;
        private DelegateCommand _SettingsCommand;


        private string _StatusMessage;
        private string _Message;

        private bool _EnableSynchronizeButton;
        private Views.MainWindow mainWindow;
        private AppUser user;

        #endregion

        #region Properties

        public DelegateCommand SettingsCommand
        {
            get
            {
                if (_SettingsCommand == null)
                    _SettingsCommand = new DelegateCommand(param => OnSettingsCommandExecuted());

                return _SettingsCommand;
            }
            set { _SettingsCommand = value; }
        }

        private void OnSettingsCommandExecuted()
        {
            Views.Settings settingView = new Views.Settings(LoggedUser, PopupInfo, PopupError);
            ((SettingsViewModel)settingView.DataContext).Changed += new EventHandler(Settings_Changed);
            settingView.Show();
        }

        void Settings_Changed(object sender, EventArgs e)
        {
            PopupInfo("Settings have been saved.", "Settings Updated.");
        }

        public AppUser LoggedUser
        {
            get { return _LoggedUser; }
            set { _LoggedUser = value; }
        }
        
        public string Message
        {
            get { return _Message; }
            set
            {
                _Message = value;
                OnPropertyChanged("Message");
            }
        }

        public DelegateCommand ExitCommand
        {
            get
            {
                if (_ExitCommand == null)
                    _ExitCommand = new DelegateCommand(param => OnExitExecuted());
                return _ExitCommand;
            }
            set { _ExitCommand = value; }
        }

        public DelegateCommand UpdateSelectedObjectCommand
        {
            get
            {
                if (_UpdateSelectedObjectCommand == null)
                    _UpdateSelectedObjectCommand = new DelegateCommand(param => UpdateSelectedObject());
                return _UpdateSelectedObjectCommand;
            }
            set { _UpdateSelectedObjectCommand = value; }
        }

        public ObservableCollection<Database> Databases
        {
            get { return _Databases; }
            set
            {
                _Databases = value;
                OnPropertyChanged("Databases");
            }
        }

        public ObservableCollection<DatabaseModel> DatabasesModel
        {
            get { return _DatabasesModel; }
            set
            {
                _DatabasesModel = value;
                OnPropertyChanged("DatabasesModel");
            }
        }

        public DbObjectModel SelectedObject
        {
            get
            {               
                return _SelectedObject;
            }
            set
            {
                _SelectedObject = value;
                OnPropertyChanged("SelectedObject");
            }

        }

        public DelegateCommand SynchronizeCommand
        {
            get
            {
                if (_SynchronizeCommand == null)
                    _SynchronizeCommand = new DelegateCommand(param => Synchronize());
                return _SynchronizeCommand;
            }
            set { _SynchronizeCommand = value; }
        }

        public DelegateCommand RefreshCommand
        {
            get
            {
                if (_RefreshCommand == null)
                    _RefreshCommand = new DelegateCommand(param => Refresh());
                return _RefreshCommand;
            }
            set { _RefreshCommand = value; }
        }
       
        public string StatusMessage
        {
            get { return _StatusMessage; }
            set
            {
                _StatusMessage = value;
                OnPropertyChanged("StatusMessage");
            }
        }

        public bool EnableSynchronizeButton
        {
            get { return _EnableSynchronizeButton; }
            set
            {
                _EnableSynchronizeButton = value;
                OnPropertyChanged("EnableSynchronizeButton");
            }
        }

        public string SourceConnectionInfo
        {
            get { return DatabaseManager.SourceConnectionInfo; }
        }

        public string PersistenceConnectionInfo
        {
            get { return DatabaseManager.PersistenceConnectionInfo; }
        }

        public string SourceStoreageName
        {
            get { return DatabaseManager.SourceStorageName; }
        }

        public string PersistenceStoreageName
        {
            get { return DatabaseManager.PersistenceStorageName; }
        }
        #endregion


        public MainViewModel(Window window, AppUser loggedUser, Action<string, string> popupInfo, Action<string, string> popupError)
        {
            LoggedUser = loggedUser;
            _CurrentView = window;
            Databases = new ObservableCollection<Database>(DatabaseManager.GetDatabases(true));
            DatabasesModel = new ObservableCollection<DatabaseModel>();
            foreach (Database db in Databases)
                DatabasesModel.Add(new DatabaseModel(db));

            StatusMessage = "Ready";
            EnableSynchronizeButton = true;
            PopupError = popupError;
            PopupInfo = popupInfo;

        }

        private object Refresh()
        {
            StatusMessage = "Started Refreshing...";
            Databases = new ObservableCollection<Database>(DatabaseManager.GetDatabases(true));
            DatabasesModel.Clear();
            foreach (Database db in Databases)
                DatabasesModel.Add(new DatabaseModel(db));
            StatusMessage = "Refreshed.";
            return null;
        }

        private object Synchronize()
        {
            Thread synchronizationThread = new Thread(SynchronizeDatabases);
            synchronizationThread.Start();
            return null;
        }

        private void SynchronizeDatabases()
        {
            EnableSynchronizeButton = false;
            StatusMessage = "Started Synchronizing...";
            lock (synchronizationObject)
            {
                DatabaseManager.Synchronize();
                Databases = new ObservableCollection<Database>(DatabaseManager.GetDatabases(true));
                Application.Current.Dispatcher.Invoke ((Action)delegate()
                {
                    DatabasesModel.Clear();
                    foreach (Database db in Databases)
                        DatabasesModel.Add(new DatabaseModel(db));
                }, null);

                StatusMessage = "Synchronization Completed.";
            }
            EnableSynchronizeButton = true;

        }

        private void UpdateSelectedObject()
        {
            StatusMessage = "Updating selected object.";
            SelectedObject.UnderlyingDbObject.Comment.ModifiedBy = LoggedUser.Username;
            SelectedObject.UnderlyingDbObject.Comment.ModifiedOn = DateTime.Now;

            // If it is a first update
            if (SelectedObject.UnderlyingDbObject.Comment.CreatedOn == DateTime.MinValue)
            {
                SelectedObject.UnderlyingDbObject.Comment.CreatedOn = DateTime.Now;
                SelectedObject.UnderlyingDbObject.Comment.CreatedBy = LoggedUser.Username;
            }

            DatabaseManager.UpdateDbObject(SelectedObject.UnderlyingDbObject);
            StatusMessage = "Updated selected object.";
        }

        private void OnExitExecuted()
        {
            IRequestExit requestExit = (IRequestExit)_CurrentView;
            if (requestExit != null)
                requestExit.ExitApplication();
        }

        private DbObject GetSelectedObject(IEnumerable<DbObject> dbObjects)
        {
            DbObject selectedObject = null;
            foreach (DbObject dbObj in dbObjects)
            {
                if (dbObj.Children == null)
                {
                    selectedObject = dbObj;
                    break;
                }
                else if (dbObj.Children != null)
                {
                    selectedObject = GetSelectedObject(dbObj.Children);
                }
            }

            return selectedObject;
        }
    }
}
